﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using AutoMapper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Net.Http.Headers;
using Newtonsoft.Json;
using Restful_Api.DtoParameters;
using Restful_Api.Entities;
using Restful_Api.Helpers;
using Restful_Api.Models;
using Restful_Api.Services;
using Restful_Api.ValidationAttributes;

namespace Restful_Api.Controllers
{
    [ApiController]
    [Route("api/Companies")]
    [Authorize]
    public class CompaniesController : ControllerBase
    {
        private readonly ICompanyRepository _companyRepository;
        private readonly IMapper _mapper;

        public CompaniesController(ICompanyRepository companyRepository, IMapper mapper)
        {
            _companyRepository = companyRepository ?? throw new ArgumentNullException(nameof(companyRepository));
            this._mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));
        }
        [HttpGet(Name = nameof(GetCompanies))]
        [HttpHead]//当时已head请求是 不会返回内容
        public async Task<IActionResult> GetCompanies([FromQuery] CompanyDtoParameters parameters)
        {
            //获取所有公司集合 api/Companies
            var companies = await _companyRepository.GetCompaniesAsync(parameters);
            var pageinationMetadata = new
            {
                totalCount = companies.TotalCount,
                pageSize = companies.PageSize,
                currentPage = companies.CurrentPage,
                totalPages = companies.TotalPages
            };
            //自定义Header
            Response.Headers.Add("X-Pageination",
                //格式化
                System.Text.Json.JsonSerializer.Serialize(pageinationMetadata, new System.Text.Json.JsonSerializerOptions()
                {
                    Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
                }));
            var links = CreateLinksForCompany(parameters, companies.HasPrevious, companies.HasNext);
            var companyDtos = _mapper.Map<List<CompanyDto>>(companies).ShapeDate(parameters.Flelds);
            var shapedCompaniesWithLinks = companyDtos.Select(x =>
            {
                var companyDict = x as IDictionary<string, object>;
                var link = CreateLinkForCompany((Guid)companyDict["Id"], null);
                companyDict.Add("Links", link);
                return companyDict;
            });
            var returnCompanyDtos = new
            {
                data = shapedCompaniesWithLinks,
                links
            };
            return Ok(returnCompanyDtos);
        }

        [HttpGet("{companyId}", Name = nameof(GetCompany))]
        //第二种写法
        //[HttpGet]
        //[Route("{companyId}")]
        public async Task<IActionResult> GetCompany(Guid companyId, string fields,
            [FromHeader(Name = "Accept")] string mediaType)//获取头部的媒体类型
        {
            if (!MediaTypeHeaderValue.TryParse(mediaType, out MediaTypeHeaderValue persedMeidaType))
            {
                return BadRequest();
            }

            //获取单个公司集合 api/Companies/{companyId}
            var company = await _companyRepository.GetCompanyAsync(companyId);
            if (company == null)
                return NotFound();

            if (persedMeidaType.MediaType == "application/vnd.company.hateoas+json")
            {
                //生成link
                var links = CreateLinkForCompany(companyId, fields);
                var companyDto = _mapper.Map<CompanyDto>(company).ShapeData(fields) as IDictionary<string, object>;
                companyDto.Add("Links", links);
                return Ok(companyDto);
            }
            return Ok(_mapper.Map<CompanyDto>(company).ShapeData(fields));
        }
        [HttpPost(Name = nameof(CreateCompany))]
        public async Task<ActionResult<CompanyDto>> CreateCompany(CompanyAddDto companyAddDto)
        {
            var company = _mapper.Map<Company>(companyAddDto);
            _companyRepository.AddCompany(company);
            await _companyRepository.SaveAsync();

            var companyDto = _mapper.Map<CompanyDto>(company);
            //生成link连接
            var links = CreateLinkForCompany(companyDto.Id, null);
            //通过自定义扩展方法 生成ExpandoObject(其实就是一组字典)
            var linksDict = companyDto.ShapeData(null) as IDictionary<string, object>;
            //给字典添加一组键值
            linksDict.Add("Links", links);
            //返回201状态码并且带着一个能找到新建的资源的路由url
            return CreatedAtRoute(nameof(GetCompany), new { companyId = companyDto.Id }, linksDict);
        }
        [HttpPost(Name = nameof(CreateCompanyAddWithBankrupTimeDto))]   
        [Consumes("application/vnd.company.companyforcreatetionwithbankrupttime+json")]
        public async Task<ActionResult<CompanyDto>> CreateCompanyAddWithBankrupTimeDto(CompanyAddWithBankrupTimeDto companyAddDto)
        {
            var company = _mapper.Map<Company>(companyAddDto);
            _companyRepository.AddCompany(company);
            await _companyRepository.SaveAsync();

            var companyDto = _mapper.Map<CompanyDto>(company);
            //生成link连接
            var links = CreateLinkForCompany(companyDto.Id, null);
            //通过自定义扩展方法 生成ExpandoObject(其实就是一组字典)
            var linksDict = companyDto.ShapeData(null) as IDictionary<string, object>;
            //给字典添加一组键值
            linksDict.Add("Links", links);
            //返回201状态码并且带着一个能找到新建的资源的路由url
            return CreatedAtRoute(nameof(GetCompany), new { companyId = companyDto.Id }, linksDict);
        }
        [HttpOptions]
        public IActionResult GetCompaniesOptions()
        {
            //在返回的头部添加一个自定义状态
            Response.Headers.Add("allow", "get,post,options");
            return Ok();
        }
        [HttpDelete("{companyId}", Name = nameof(DeleteCompany))]
        public async Task<IActionResult> DeleteCompany(Guid companyId)
        {
            var companyEntity = await _companyRepository.GetCompanyAsync(companyId);

            if (companyEntity == null)
                return NotFound();
            _companyRepository.DeleteCompany(companyEntity);
            await _companyRepository.SaveAsync();
            return NoContent();
        }
        //用于给响应头部 添加上一页和下一页的连接
        private string CreateCompaniesResourceUrl(CompanyDtoParameters parameters, ResourceUrlType type)
        {
            switch (type)
            {
                case ResourceUrlType.PreviousPage:
                    return Url.Link(nameof(GetCompanies), new
                    {
                        Flelds = parameters.Flelds,
                        OrderBy = parameters.OrderBy,
                        pageNum = parameters.PageNum - 1,
                        pageSize = parameters.PageSize,
                        companyName = parameters.CompanyName,
                        searchTerm = parameters.SearchTerm
                    });
                case ResourceUrlType.NextPage:
                    return Url.Link(nameof(GetCompanies), new
                    {
                        Flelds = parameters.Flelds,
                        OrderBy = parameters.OrderBy,
                        pageNum = parameters.PageNum + 1,
                        pageSize = parameters.PageSize,
                        companyName = parameters.CompanyName,
                        searchTerm = parameters.SearchTerm
                    });
                case ResourceUrlType.CurrentPage:
                    {
                        return Url.Link(nameof(GetCompanies), new
                        {
                            Flelds = parameters.Flelds,
                            OrderBy = parameters.OrderBy,
                            pageNum = parameters.PageNum,
                            pageSize = parameters.PageSize,
                            companyName = parameters.CompanyName,
                            searchTerm = parameters.SearchTerm
                        });
                    }
                default:
                    {
                        throw new Exception("走不到这");
                    }
            }
        }
        //针对单个资源生成Link
        private IEnumerable<LinkDto> CreateLinkForCompany(Guid companyId, string fields)
        {
            var links = new List<LinkDto>();
            if (string.IsNullOrWhiteSpace(fields))
            {
                links.Add(new LinkDto(Url.Link(nameof(GetCompany), new { companyId }), "self", "Get"));
            }
            else
            {
                links.Add(new LinkDto(Url.Link(nameof(GetCompany), new { companyId, fields }), "self", "Get"));
            }
            links.Add(new LinkDto(
                Url.Link(nameof(DeleteCompany),
                new { companyId }), "Delete_company",
                "Delete"));

            links.Add(new LinkDto(
                Url.Link(nameof(EmployeeController.CreateEmployeeForCompany),
                new { companyId }), "Create_employee_forCompany",
                "Post"));

            links.Add(new LinkDto(
              Url.Link(nameof(EmployeeController.GetEmployeesForCompany),
              new { companyId }), "employees",
              "Get"));

            return links;
        }

        private IEnumerable<LinkDto> CreateLinksForCompany(CompanyDtoParameters parameters, bool hasPrevious, bool nextPage)
        {
            var links = new List<LinkDto>();
            links.Add(new LinkDto(
                CreateCompaniesResourceUrl(parameters, ResourceUrlType.CurrentPage),
                "selt"
                , "Get"));
            if (hasPrevious)
            {
                links.Add(new LinkDto(
              CreateCompaniesResourceUrl(parameters, ResourceUrlType.PreviousPage),
              "previous_page"
              , "Get"));
            }
            if (nextPage)
            {
                links.Add(new LinkDto(
              CreateCompaniesResourceUrl(parameters, ResourceUrlType.NextPage),
              "nextpage_page"
              , "Get"));
            }
            return links;
        }

    }
}
